package com.tqz.rc.server.healthcheck;

import com.tqz.rc.api.Instance;
import com.tqz.rc.common.constant.DefaultValueConstant;
import com.tqz.rc.common.util.ApplicationContextUtil;
import com.tqz.rc.common.util.DateUtil;
import com.tqz.rc.server.consistency.KeyBuilder;
import com.tqz.rc.server.core.DistroMapper;
import com.tqz.rc.server.core.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * <p>在初始化某一个服务的的时候，服务端自行开启一个定时任务去执行客户端心跳健康检查任务。
 * 默认延时5秒钟执行，每5秒钟执行一次，心跳时间超过15秒就把该实例设置为不健康状态，超过30秒就剔除该服务。
 *
 * @author tianqingzhao
 * @since 2021/8/31 15:22
 */
public class ClientBeatCheckTask implements BeatCheckTask {

    private static final Logger log = LoggerFactory.getLogger(ClientBeatCheckTask.class);

    private Service service;

    public ClientBeatCheckTask(Service service) {
        this.service = service;
    }

    @Override
    public String taskKey() {
        return KeyBuilder.buildServiceMetaKey(service.getNamespaceId(), service.getServiceName());
    }

    @Override
    public void run() {
        if (log.isDebugEnabled()) {
            log.debug("服务端定时处理客户端心跳的时间：{}", DateUtil.getCurDateTime());
        }

        // server端集群根据客户端的服务名称取模，选择server端集群里面的一台机器进行健康检查
        if (!getDistroMapper().responsible(service.getServiceName())) {
            return;
        }

        List<Instance> instances = service.allIps(true);
        if (instances.size() <= 0) {
            log.info("服务列表为空。");
            return;
        }

        for (Instance instance : instances) {
            if (System.currentTimeMillis() - instance.getLastBeat() > DefaultValueConstant.INSTANCE_HEART_BEAT_TIME_OUT) {
                if (instance.isHealthy()) {
                    instance.setHealthy(false);

                    log.warn("设置 intanceId：{}, ip：{}, port：{} 实例为不健康状态。", instance.getInstanceId(), instance.getIp(), instance.getPort());

                    // 向订阅的服务发送服务变更的事件
                    service.getUdpPushService().serviceChanged(service);
                }
            }
        }

        for (Instance instance : instances) {
            if (System.currentTimeMillis() - instance.getLastBeat() > DefaultValueConstant.IP_DELETE_TIME_OUT) {

                log.warn("删除 intanceId：{}, ip：{}, port：{} 实例。", instance.getInstanceId(), instance.getIp(), instance.getPort());

                // 本机删除该实例
                deleteIp(instance, instances);
            }
        }
    }

    private DistroMapper getDistroMapper() {
        return ApplicationContextUtil.getBean(DistroMapper.class);
    }

    /**
     * 删除实例。
     *
     * @param instance  实例对象
     * @param instances 当前集群的实例集合
     */
    private void deleteIp(Instance instance, List<Instance> instances) {

        // TODO 这种方式删除不掉
        instances.remove(instance);

        try {
            // TODO 通过http方式向本机发送该实例被剔除，最终还会会调用到onPut方法
//            throw new Exception("自己抛出的异常。。。");
        } catch (Exception e) {
            System.out.println("[IP-DEAD] failed to delete ip automatically, ip: " + instance.toJson() + ", error: " + e);
        }
    }
}
